using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

//编辑一个父类，提供一个与lua脚本进行交互的c#脚本的基本框架，提供通用方法和属性
public class LuaBehaviour : MonoBehaviour
{
    //引用全局的Lua虚拟机(在lua管理器中)
    private LuaEnv m_luaEnv = Manager.Lua.LuaEnv;
    //权限为protected的lua脚本环境，用于子类调用
    //在Unity的C#脚本中，字段的初始值设定在类的加载阶段执行，此时非静态字段尚未被创建。因此不能引用非静态字段
    //protected LuaTable m_ScriptEnv = m_luaEnv.NewTable();
    protected LuaTable m_ScriptEnv;

    //private Action m_LuaAwake;
    //private Action m_LuaStart;
    private Action m_LuaOnInit;
    private Action m_LuaUpdate;
    private Action m_LuaOnDestroy;

    //！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！
    //如果我想通过一个api把unity预设和lua脚本绑定，并且执行这个脚本。在使用awake的情况下，在awake之前传入lua脚本名，只能通过这种方式实现
    //public string luaName;
    //但是这种方式不是一个框架的做法，因为这样会导致lua脚本和unity预设绑定在一起，不利于lua脚本的复用
    //无法直接使用awake和start，需要自己编写函数，模拟awake和start的特性
    //awake：实例化执行一次——用于加载数据配置；start：实例化和激活都会执行——用于刷新ui

    private void Awake()
    {
        Debug.Log("LuaBehaviour Awake");
        m_ScriptEnv = m_luaEnv.NewTable();
        //为每个脚本设置一个独立的lua环境，避免脚本之间全局变量的冲突
        //设置元表，用于查找全局变量
        LuaTable meta = m_luaEnv.NewTable();
        meta.Set("__index", m_luaEnv.Global);
        m_ScriptEnv.SetMetaTable(meta);
        //m_ScriptEnv与元表的引用关系已经建立，因此可以释放元表
        meta.Dispose();

        //在lua环境中设置一个self变量，指向当前的LuaBehaviour子类实例
        m_ScriptEnv.Set("self", this);

        //将下列代码放到Init函数中
        //m_luaEnv.DoString(Manager.Lua.GetLuaScript(luaName), luaName, m_ScriptEnv);

        //m_ScriptEnv.Get("Awake", out m_LuaAwake);
        //m_ScriptEnv.Get("Start", out m_LuaStart);
        //m_ScriptEnv.Get("Update", out m_LuaUpdate);
        //m_ScriptEnv.Get("OnDestroy", out m_LuaOnDestroy);

        //m_LuaAwake?.Invoke();
    }

    //模拟awake的特性(start写在子类),允许子类重写
    //传入一个lua脚本名。加载lua脚本，并进行通用的基本lua函数与c#委托的绑定，用于后续调用。
    //子类可添加其他绑定
    public virtual void Init(string luaName)
    {
        m_luaEnv.DoString(Manager.Lua.GetLuaScript(luaName), luaName, m_ScriptEnv);

        //这两个函数就没用了
        //m_ScriptEnv.Get("Awake", out m_LuaAwake);
        //m_ScriptEnv.Get("Start", out m_LuaStart);
        m_ScriptEnv.Get("OnInit", out m_LuaOnInit);
        m_ScriptEnv.Get("Update", out m_LuaUpdate);
        m_ScriptEnv.Get("OnDestroy", out m_LuaOnDestroy);
        //m_LuaAwake?.Invoke();
        m_LuaOnInit?.Invoke();
    }

    //void Start()
    //{
    //    m_LuaStart?.Invoke();
    //}

    void Update()
    {
        m_LuaUpdate?.Invoke();
    }

    //回收的方法，当对象被销毁时调用
    //子类继承时可能需要重写，可能有更多的对象，但是不会直接调用，在类内部放在销毁函数进行封装
    protected virtual void Clear()
    {
        //把所有函数置为null，释放资源，否则会报错
        m_LuaOnInit = null;
        m_LuaOnDestroy = null;
        m_LuaUpdate = null;
        //m_LuaStart = null;
        //m_LuaAwake = null;
        // 释放Lua环境所占用的资源  
        m_ScriptEnv?.Dispose();
        ///将引用置为null，防止后续访问
        m_ScriptEnv = null;
    }

    void OnDestroy()
    {
        m_LuaOnDestroy?.Invoke();
        Clear();
    }
    void OnApplicationQuit()
    {
        Clear();
    }

}
